using System.Collections;
using System.Collections.Generic;
using System.Text;

#pragma warning disable 1591 // TODO CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member'

namespace Fizzler.Model
{
    public static class Selectors
    {
        public static ISelectorGroup Group(params ISimpleSelectorChain[] selectors)
        {
            return new SelectorGroup((ISimpleSelectorChain[]) selectors.Clone());
        }
        public static ISimpleSelectorChain Chain(
                ISimpleSelectorChainPrimary primary, 
                params ISimpleSelectorChainSecondary[] secondaries)
        {
            return new SimpleSelectorChain(primary, (ISimpleSelectorChainSecondary[]) secondaries.Clone());
        }
        public static IUniversalSelector Universal() 
        {
            return new UniversalSelector(); 
        }
        public static ITypeSelector Type(string type)
        {
            return new TypeSelector(type);
        }
        public static IIdSelector Id(string id)
        {
            return new IdSelector(id);
        }
        public static IClassSelector Class(string clazz)
        {
            return new ClassSelector(clazz);
        }
        public static IAttributeDefinedSelector Attribue(string name)
        {
            return new AttributeDefinedSelector(name);
        }
        public static IAttributeExactSelector AttributeExact(string name, string value)
        {
            return new AttributeExactSelector(name, value);
        }

        private sealed class SelectorGroup : ISelectorGroup
        {
            private readonly IEnumerable<ISimpleSelectorChain> _selectors;

            public SelectorGroup(IEnumerable<ISimpleSelectorChain> selectors)
            {
                _selectors = selectors;
            }

            public IEnumerator<ISimpleSelectorChain> GetEnumerator()
            {
                return _selectors.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            public override string ToString()
            {
                var sb = new StringBuilder();
                foreach (var selector in this)
                {
                    if (sb.Length > 0)
                        sb.Append(", ");
                    sb.Append(selector);
                }
                return sb.ToString();
            }
        }
        private sealed class SimpleSelectorChain : ISimpleSelectorChain
        {
            public ISimpleSelectorChainPrimary Primary { get; private set; }
            public IEnumerable<ISimpleSelectorChainSecondary> Secondaries { get; private set; }

            public SimpleSelectorChain(ISimpleSelectorChainPrimary primary, 
                                       IEnumerable<ISimpleSelectorChainSecondary> secondaries)
            {
                Primary = primary;
                Secondaries = secondaries;
            }

            public override string ToString()
            {
                var sb = new StringBuilder();
                sb.Append(Primary);
                foreach (var link in Secondaries)
                    sb.Append(link);
                return sb.ToString();
            }
        }
        private sealed class UniversalSelector : IUniversalSelector
        {
            public override string ToString()
            {
                return "*";
            }
        }
        private sealed class TypeSelector : ITypeSelector
        {
            public string Type { get; private set; }

            public TypeSelector(string type)
            {
                Type = type;
            }

            public override string ToString()
            {
                return Type;
            }
        }
        private sealed class IdSelector : IIdSelector
        {
            public string Id { get; private set; }

            public IdSelector(string id)
            {
                Id = id;
            }

            public override string ToString()
            {
                return "#" + Id;
            }
        }
        private sealed class ClassSelector : IClassSelector
        {
            public string Class { get; private set; }

            public ClassSelector(string clazz)
            {
                Class = clazz;
            }

            public override string ToString()
            {
                return "." + Class;
            }
        }
        private abstract class AttributeSelector : IAttributeSelector
        {
            public string Name { get; private set; }
            public string Value { get; private set; }

            protected AttributeSelector(string name, string value)
            {
                Name = name;
                Value = value;
            }

            protected string ToStringImpl(string op)
            {
                var sb = new StringBuilder(2 + Name.Length + (op != null ? Value.Length + 2 : 0));
                sb.Append('[').Append(Name);
                if (op != null)
                    sb.Append(op).Append(Value);
                return sb.Append(']').ToString();
            }
        }
        private sealed class AttributeDefinedSelector : AttributeSelector, IAttributeDefinedSelector
        {
            public AttributeDefinedSelector(string name) :
                    base(name, null) {}

            public override string ToString()
            {
                return ToStringImpl(null);
            }
        }
        private sealed class AttributeExactSelector : AttributeSelector, IAttributeExactSelector
        {
            public AttributeExactSelector(string name, string value) :
                    base(name, value) { }

            public override string ToString()
            {
                return ToStringImpl("=");
            }
        }
        private sealed class AttributeWordSelector : AttributeSelector, IAttributeWordSelector
        {
            public AttributeWordSelector(string name, string value) :
                    base(name, value) { }

            public override string ToString()
            {
                return ToStringImpl("~=");
            }
        }
        private sealed class AttributeDashSelector : AttributeSelector, IAttributeDashSelector
        {
            public AttributeDashSelector(string name, string value) :
                    base(name, value) { }

            public override string ToString()
            {
                return ToStringImpl("|=");
            }
        }
        private sealed class FirstChildSelector : IFirstChildSelector
        {
            public override string ToString()
            {
                return ":first-child";
            }
        }
        private sealed class LastChildSelector : ILastChildSelector
        {
            public override string ToString()
            {
                return ":last-child";
            }
        }
        private sealed class OnlyChildSelector : IOnlyChildSelector
        {
            public override string ToString()
            {
                return ":only-child";
            }
        }
        private sealed class EmptySelector : IEmptySelector
        {
            public override string ToString()
            {
                return ":empty";
            }
        }
    }
}